#ifndef __M_EXCHANGE_H__
#define __M_EXCHANGE_H__

#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <google/protobuf/map.h>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <vector>

namespace mymq
{
    // 1.定义交换机类
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>;

        std::string name;// 名称
        ExchangeType type;// 类型
        bool durable;// 交换机持久化标志
        bool auto_delete;// 是否自动删除标志
        google::protobuf::Map<std::string, std::string> args;// 其他参数

        Exchange(){}

        Exchange(const std::string& ename,ExchangeType etype,
        bool edurable,bool eauto_delete,
        const google::protobuf::Map<std::string, std::string>& eargs)
        :name(ename),type(etype),durable(edurable),auto_delete(eauto_delete),args(eargs)
        {}

        // args存储键值对，在存储数据库时，会组织一个格式字符串进行存储 key=val&key=val...
        void setArgs(const std::string& str_args)// 解析str_args，存储到成员args中
        {
            std::vector<std::string> sub_args;
            size_t ret = StrHelper::split(str_args,"&",sub_args);
            for(auto& str:sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0,pos);
                std::string value = str.substr(pos+1);
                args[key] = value;
            }
        }

        // 将args中的内容进行序列化后（key=val&key=val...）返回一个字符串
        std::string getArgs()
        {
            std::string result;
            for(auto start = args.begin();start != args.end();start++)
            {
                result += start->first + "=" + start->second + "&";
            }
            return result;
        }
    };

    using ExchangeMap = std::unordered_map<std::string,Exchange::ptr>;
    // 2.定义交换机数据持久化管理类--数据存储在sqlite数据库中
    class ExchangeMapper
    {
        public:
            ExchangeMapper(const std::string& dbfile):_sql_helper(dbfile)
            {
                std::string path = mymq::FileHelper::parentDirectory(dbfile);
                FileHelper::createDirectory(path);
                assert(_sql_helper.open());
                createTable();
            }

            void createTable()
            {
                #define CREATE_TABLE "create table if not exists exchange_table(\
                name varchar(32) primary key, \
                type int,\
                durable int,\
                auto_delete int,\
                args varchar(128));"

                bool ret = _sql_helper.exec(CREATE_TABLE,nullptr,nullptr);
                if(ret == false)
                {
                    DLOG("创建交换机数据库失败！");
                    abort();// 直接异常退出程序
                }
            }

            void removeTable()
            {
                #define DROP_TABLE "drop table if exists exchange_table;"
                bool ret = _sql_helper.exec(DROP_TABLE,nullptr,nullptr);
                if(ret == false)
                {
                    DLOG("删除交换机数据库失败！");
                    abort();// 直接异常退出程序
                }
            }

            bool insert(Exchange::ptr& exp)
            {
                std::stringstream ss;
                ss << "insert into exchange_table values(";
                ss << "'" << exp->name << "', ";
                ss << exp->type << ", ";
                ss << exp->durable << ", ";
                ss << exp->auto_delete << ", ";
                ss << "'" << exp->getArgs() << "');";
                return _sql_helper.exec(ss.str(), nullptr, nullptr);
            }

            void remove(const std::string& name)
            {
                // C++写法
                std::stringstream ss;
                ss << "delete from exchange_table where name=";
                ss << "'" << name << "';";
                _sql_helper.exec(ss.str(),nullptr,nullptr);
            }
            
            ExchangeMap recovery()
            {
                ExchangeMap result;
                std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
                _sql_helper.exec(sql,selectCallback,&result);
                return result;
            }

        private:
            static int selectCallback(void* arg,int numcol,char** row,char** fields)
            {
                ExchangeMap* result = (ExchangeMap*)arg;
                auto exp = std::make_shared<Exchange>();
                exp->name = row[0];
                exp->type = (mymq::ExchangeType)std::stoi(row[1]);
                exp->durable = (bool)std::stoi(row[2]);
                exp->auto_delete = (bool)std::stoi(row[3]);
                if(row[4]) exp->setArgs(row[4]); // 为空则不设置，否则容易出问题
                result->insert(std::make_pair(exp->name,exp));
                return 0;
            }
 
        private:
            SqliteHelper _sql_helper;
    };

    // 3.定义交换机数据内存管理类，真正对外的，可能被多线程同时执行的
    class ExchangeManager
    {
        public:
            using ptr = std::shared_ptr<ExchangeManager>;
            
            ExchangeManager(const std::string& dbfile):_mapper(dbfile)
            {
                _exchanges = _mapper.recovery();
            }

            // 声明交换机（存在就创建）
            bool declareExchange(const std::string& name,ExchangeType type,
            bool durable,bool auto_delete,const google::protobuf::Map<std::string, std::string>& args)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _exchanges.find(name);
                if(it != _exchanges.end())
                {
                    // 如果交换机已经存在，则直接返回，不必重复新增
                    return true;
                }
                auto exp = std::make_shared<Exchange>(name,type,durable,auto_delete,args);
                if(durable == true)
                {
                    bool ret = _mapper.insert(exp);
                    if(ret == false) return false;
                }
                _exchanges.insert(std::make_pair(name,exp));
                return true;
            }
            
            // 删除交换机
            void deleteExchange(const std::string& name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _exchanges.find(name);
                if(it != _exchanges.end())
                {
                    if(it->second->durable == true) 
                    {
                        _mapper.remove(name);
                    }
                    _exchanges.erase(name);
                }
                // 若交换机不存在则直接返回
                return;
            }

            // 获取指定交换机对象
            Exchange::ptr selectExchange(const std::string& name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _exchanges.find(name);
                if(it != _exchanges.end())
                {
                    // 如果交换机已经存在，则直接返回
                    return it->second;
                }
                return Exchange::ptr();
            }
            
            // 判断交换机是否存在
            bool exists(const std::string& name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _exchanges.find(name);
                if(it != _exchanges.end())
                {
                    // 如果交换机已经存在，则直接返回
                    return true;
                }
                return false;
            }

            size_t size()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                return _exchanges.size();
            }
            
            // 清理所有交换机数据
            void clear()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _mapper.removeTable();
                _exchanges.clear();
            }

        private:
            std::mutex _mutex; // 保护线程安全
            ExchangeMapper _mapper;
            ExchangeMap _exchanges;
    };

}

#endif